; *******************************************************************
; * exp4_2.asm
; * LLP STUDIO Chen Zhepeng
; * V1.0
; * 2023-11-18
; * 启动后点亮LED1，用中断方式实现
; * 按下KEY1，LED循环右移；按下KEY2，循环左移
; *******************************************************************

P4         DATA 0C0H
P6         DATA 0E8H
P4M1       DATA 0B3H
P4M0       DATA 0B4H
P6M1       DATA 0CBH
P6M0       DATA 0CCH
HC595_SI   BIT  P4.4  ; 74HC595串行输入端
HC595_SCK  BIT  P4.2  ; 74HC595移位时钟输入
HC595_RCK  BIT  P4.3  ; 74HC595锁存时钟输入
led_state  DATA 42H  ; 8个LED灯的状态

ORG 0000H
LJMP Main
ORG 0003H
LJMP Int0Isr
ORG 0013H
LJMP Int1Isr
ORG 0100H
Main:
; P4口推挽
MOV P4M1, #00H
MOV P4M0, #0FFH
; 设置P6口为推挽输出
MOV P6M1, #00H
MOV P6M0, #0FFH
MOV SP, #80H
LCALL Hc595Off
CLR P4.0  ; 允许LED显示
CLR IE1
CLR IE0
SETB EX1
SETB EX0
; 下降沿中断
SETB IT0
SETB IT1
SETB EA
MOV led_state, #0FEH  ; 点亮LED1
MainLoop:
MOV P6, led_state
SJMP MainLoop

; * @brief       向74HC595D发送一个字节
; * @param       ACC: 要发送的字节数据（存放在累加器中）
; * @retval      无
Hc595SendByte:
PUSH 02H
MOV R2, #8
Hc595SendLoop:
RLC A
MOV HC595_SI, C
SETB HC595_SCK
CLR HC595_SCK
DJNZ R2, Hc595SendLoop
POP 02H
RET

; * @brief       关闭74HC595D
; * @param       无
; * @retval      无
Hc595Off:
PUSH ACC
; 输出点阵位码，关闭LED点阵
CLR A
LCALL Hc595SendByte
; 输出数码管位码，关闭数码管
CLR A
LCALL Hc595SendByte
CLR HC595_RCK
NOP
SETB HC595_RCK  ; 输入数据上升沿锁存到输出端
CLR HC595_RCK  ; 锁存输出数据
POP ACC
RET

; * @brief       INT0中断服务子程序
; * @param       无
; * @retval      无
Int0Isr:
MOV A, led_state
RL A
MOV led_state, A
Int0Sub:
JNB P3.2, $
MOV A, #00H
; 延时1 / (24 * 10^6) * (2 * 255 + 3 * 1) = 21.375 μs
DJNZ ACC, $
JNB P3.2, Int0Sub
RETI

; * @brief       INT1中断服务子程序
; * @param       无
; * @retval      无
Int1Isr:
MOV A, led_state
RR A
MOV led_state, A
Int1Sub:
JNB P3.3, $
MOV A, #00H
DJNZ ACC, $
JNB P3.3, Int1Sub
RETI

END